/* The file is saved in UTF-8 codepage.
 * Check: «Stereotype», Section mark-§, Copyright-©, Alpha-α, Beta-β, Smile-☺
 */
package cz.pecinovsky.english.lootp._134_;

import cz.pecinovsky.english.lootp._parents._ITrafficLight_134_;

import cz.pecinovsky.english.lootp.manager.CanvasManager_Envelope.CanvasManager;
//import cz.pecinovsky.english.lootp.manager.   IMoveable;
import cz.pecinovsky.english.lootp.manager.     Painter;
import cz.pecinovsky.english.lootp.manager.     Rectangle;


//import cz.pecinovsky.english.lootp._134_.IModulový_134_.        IModular;
import cz.pecinovsky.english.lootp._134_.IRotable_136_.         IRotable;
import cz.pecinovsky.english.lootp._134_.Light_134_.            Light;
import cz.pecinovsky.english.lootp._134_.TrafficLightState_142_.TrafficLightState;


import static cz.pecinovsky.english.lootp.
              _134_.TrafficLightState_142_.TrafficLightState.*;



//import cz.pecinovsky.english.lootp._134_.TrafficLight_134_.TrafficLight;
////////////////////////////////////////////////////////////////////////////////
//%%+  +++++ End of ignored starting test - place for imports +++++
//%I+ >=132z
//
//import cz.pecinovsky.english.lootp.canvasmanager.IMoveable;
//import cz.pecinovsky.english.lootp.canvasmanager.Painter;
//import cz.pecinovsky.english.lootp.canvasmanager.Rectangle;
//import cz.pecinovsky.english.lootp.canvasmanager.CanvasManager;
//%I-

import cz.pecinovsky.english.lootp.utility.NamedColor;
import cz.pecinovsky.english.lootp.utility.IO;
//%A+ >136
import cz.pecinovsky.english.lootp.utility.Area;
//%A-
import cz.pecinovsky.english.lootp.utility.Position;
//%A+ >136
import cz.pecinovsky.english.lootp.utility.Direction8;
//%A-
//%I+ >142
//
//
//import cz.pecinovsky.english.lootp.town.TrafficLightState.*;
//%I-
//%X+ xxxxx Start of the ovejumped text with declaration of the envelope xxxxx
/*******************************************************************************
 *<pre>
 * Předchozí:   oopnz._115_._116_Semafor_119
 * Následující: Prozatím není
 *
 * Projekt  020z - Komentáře
 *   + Začlenění do standardní šablony + Komentáře
 *
 * Projekt  021z - Použití this
 *   ~ V prvních dvou konstruktorech nahrazena původní těla
 *     příkazem this volajícím obecnější konstruktor
 *
 * Projekt  022z - Přetěžování
 *   + Přidány další dva konstruktory
 *   ~ Ve třetím konstruktoru nahrazeno tělo příkazem this
 *     volající přidaný obecnější konstruktor
 *
 * Projekt  Ppp
 *   + Přidáno
 *   - Odebráno
 *   ~ Změněno
 *</pre>
 */
public class TrafficLight_134_
{    private TrafficLight_134_() {}   static
////////////////////////////////////////////////////////////////////////////////
//%X- ----- End of the ovejumped text with declaration of the envelope -----


/*******************************************************************************
 * Instance třídy {@code TrafficLight} představují trafficLighty obdobné těm,
 * které řídí dopravu na křižovatkách.
 *
 * @author Rudolf PECINOVSKÝ
 * @version 6.03.2017 — 2010-11-08
 */
//%I+ <136
//public class TrafficLight implements IModular
//%I-
//%A+ >136
public class TrafficLight implements IRotable
//%A-
//%A+ <0
        ,   _ITrafficLight_134_
//%A-
     {
//== CONSTANT CLASS ATTRIBUTES =================================================

    private static final int DEFAULT_X = 0;

    private static final int DEFAULT_Y = 0;

    private static final int DEFAULT_MODUL = 50;

    private static final NamedColor DEFAULT_BOX_COLOR = NamedColor.BLACK;
//%A+ >136

    private static final Direction8 DEFAULT_DIRECTION = Direction8.EAST;

    /** Canvas, na které se bude instance kreslit. */
    private static final CanvasManager CM = CanvasManager.getInstance();
//%A-



//== VARIABLE CLASS ATTRIBUTES =================================================

     /** Počet doposud vytvořených instancí. */
     private static int countCreated = 0;



//== STATIC CONSTRUCTOR (CLASS INITIALIZER, STATIC INICITALIZING BLOCK) ========
//== CONSTANT INSTANCE ATTRIBUTES ==============================================

    /** Pořadové (identifikační) číslo dané instance. */
    private final int ID;

    /** Krabice, v níž jsou umístěna světla. */
    private final Rectangle box;

    /** Horní, červené light. */
    private final Light redLight;

    /** Střední, žluté (oranžové) light. */
    private final Light amberLight;

    /** Dolní, zelené light. */
    private final Light greenLight;



//== VARIABLE INSTANCE ATTRIBUTES ==============================================

    /** Název instance sestávající implicitně z názvu třídy a ID instance */
    private String name;
//%A+ >136

    /** Bodová x-ová souřadnice instance. */
    private int xPos;

    /** Bodová y-ová souřadnice instance. */
    private int yPos;

    /** Velikost strany čverce vyplněného šipkou v bodech. */
    private int module;

    /** Směr, do nějž je arrow natočena. */
    private Direction8 direction;
//%A-
//%A+ >142

    /** Stav, v němž se trafficLight právě nachází. */
    private TrafficLightState state;
//%A-



//== CLASS GETTERS AND SETTERS =================================================
//== OTHER NON-PRIVATE CLASS METHODS ===========================================

//##############################################################################
//== CONSTUCTORS AND FACTORY METHODS ===========================================

    /***************************************************************************
     * Vytvoří trafficLight implicitních rozměrů a barvy
     * umístěný v levém horním rohu plátna.
     */
    public TrafficLight()
    {
        this(DEFAULT_X, DEFAULT_Y);
    }


    /***************************************************************************
     * Vytvoří trafficLight implicitních rozměrů a barvy
     * umístěný na zadané pozici.
     *
     * @param x  Vodorovná souřadnice
     * @param y  Svislá souřadnice
     */
    public TrafficLight(int x, int y)
    {
        this(x, y, DEFAULT_BOX_COLOR);
    }


    /***************************************************************************
     * Vytvoří trafficLight implicitních rozměrů s krabicí zadané barvy
     * umístěný na zadané pozici.
     *
     * @param x  Vodorovná souřadnice
     * @param y  Svislá souřadnice
     * @param boxColor  Požadovaná color box se světly
     */
    public TrafficLight(int x, int y, NamedColor boxColor)
    {
        this(x, y, DEFAULT_MODUL, boxColor);
    }


    /***************************************************************************
     * Vytvoří trafficLight zadaných rozměrů s krabicí implicitní barvy
     * umístěný na zadaných souřadnicích.
     *
     * @param x  Vodorovná souřadnice
     * @param y  Svislá souřadnice
//%I+ <136
//     * @param module Šířka trafficLightu a diameter jeho světel
//%I-
//%A+ >136
     * @param module Strana čtvercovéhzo políčka, v němž bude trafficLight umístěn,
     *              width trafficLightu a diameter jeho světel je 1/4 této velikosti
//%A-
     */
    public TrafficLight(int x, int y, int module)
    {
        this(x, y, module, DEFAULT_BOX_COLOR);
    }

//%A+ >136

    /***************************************************************************
     * Vytvoří trafficLight zadaných rozměrů s krabicí implicitní barvy
     * umístěný na zadaných souřadnicích a natočený do zadaného směru.
     *
     * @param x  Vodorovná souřadnice
     * @param y  Svislá souřadnice
     * @param module Strana čtvercovéhzo políčka, v němž bude trafficLight umístěn,
     *              width trafficLightu a diameter jeho světel je 1/4 této velikosti
     * @param direction  Směr, do nějž bude vytvořený trafficLight natočen
     */
    public TrafficLight(int x, int y, int module, Direction8 direction)
    {
        this(x, y, module, DEFAULT_BOX_COLOR, direction);
    }

//%A-

    /***************************************************************************
     * Vytvoří trafficLight zadaných rozměrů s krabicí zadané barvy
     * umístěný na zadaných souřadnicích.
     *
     * @param x  Vodorovná souřadnice
     * @param y  Svislá souřadnice
//%I+ <136
//     * @param module Šířka trafficLightu a diameter jeho světel
//%I-
//%A+ >136
     * @param module Strana čtvercovéhzo políčka, v němž bude trafficLight umístěn,
     *              width trafficLightu a diameter jeho světel je 1/4 této velikosti
//%A-
     * @param boxColor  Požadovaná color box se světly
     */
    public TrafficLight(int x, int y, int module, NamedColor boxColor)
    {
//%I+ <136
//        countCreated   = countCreated + 1;
//        this.ID = countCreated;
//
//        box = new Rectangle(x, y,  module, 3*module, boxColor);
//
//        redLight = new Light  (x, y,         module, NamedColor.RED, NamedColor.ŽÁDNÁ);
//        amberLight   = new Light  (x, y+  module, module, NamedColor.YELLOW,   NamedColor.ŽÁDNÁ);
//        greenLight  = new Light  (x, y+2*module, module, NamedColor.GREEN,  NamedColor.ŽÁDNÁ);
//    }
//%I-
//%A+ >136
        this(x, y, module, DEFAULT_BOX_COLOR, DEFAULT_DIRECTION);
    }


    /***************************************************************************
     * Vytvoří trafficLight zadaných rozměrů s krabicí zadané barvy
     * umístěný na zadaných souřadnicích a otočený zadaným směrem.
     *
     * @param x  Vodorovná souřadnice
     * @param y  Svislá souřadnice
     * @param module Strana čtvercovéhzo políčka, v němž bude trafficLight umístěn,
     *              width trafficLightu a diameter jeho světel je 1/4 této velikosti
     * @param boxColor  Požadovaná color box se světly
     * @param direction  Směr, do nějž bude vytvořený trafficLight natočen
     */
    public TrafficLight(int x, int y, int module, NamedColor boxColor, Direction8 direction)
    {
        countCreated = countCreated + 1;
        this.ID = countCreated;

        this.xPos  = x;
        this.yPos  = y;
        this.module = module;
        this.direction  = direction;

        int m1 = module;
        int m2 = module / 2;
        int m4 = module / 4;
        int m34= 3 * module / 4;

        Area ref = new Area(x, y, module, module);
        Area part;

        //box
        part = new Area(m4, 0, m34, m4);
        part = direction.turnInArea(part, ref);
        this.box = new Rectangle(part, boxColor);

        //redLight
        part = new Area(m34, 0, m4, m4);
        part = direction.turnInArea(part, ref);
        this.redLight = new Light(part.x, part.y, part.height,
                                  NamedColor.RED, NamedColor.NO);

        //amberLight
        part = new Area(m2, 0, m4, m4);
        part = direction.turnInArea(part, ref);
        this.amberLight = new Light(part.x, part.y, part.height,
                                NamedColor.YELLOW, NamedColor.NO);

        //greenLight
        part = new Area(m4, 0, m4, m4);
        part = direction.turnInArea(part, ref);
        this.greenLight = new Light(part.x, part.y, part.height,
                                 NamedColor.GREEN, NamedColor.NO);
//%A-
//%A+ >142

        //Budeme začínat se zhasnutým trafficLightem
        allLightsOff();
//%A-
//%A+ >136
    }
//%A-



//== ABSTRACT METHODS ==========================================================
//== INSTANCE GETTERS AND SETTERS ==============================================

    // Sada přístupových metod vlastnosti: Position ******************************

    /***************************************************************************
     * Vrátí x-ovou (vodorovnou) souřadnici pozice instance.
     *
     * @return  x-ová souřadnice.
     */
//%A+ <"
    @Override
//%A-
    public int getX()
    {
//%I+ <136
//        return box.getX();
//%I-
//%A+ >136
        return xPos;
//%A-
    }


    /***************************************************************************
     * Vrátí y-ovou (svislou) souřadnici pozice instance.
     *
     * @return  y-ová souřadnice.
     */
//%A+ <"
    @Override
//%A-
    public int getY()
    {
//%I+ <136
//        return box.getY();
//%I-
//%A+ >136
        return yPos;
//%A-
    }


    /***************************************************************************
     * Vrátí přepravku se svojí aktuální pozicí.
     *
     * @return Aktuální pozice světla
     */
    @Override
    public Position getPosition()
    {
        return new Position(getX(), getY());
    }


    /***************************************************************************
     * Nastaví novou pozici světla.
     *
     * @param p Nastavovaná pozice
     */
    @Override
    public void setPosition(Position p)
    {
        this.setPosition(p.x, p.y);
    }


    /***************************************************************************
     * Nastaví novou pozici instance.
     *
     * @param x   Nová x-ová pozice instance
     * @param y   Nová y-ová pozice instance
     */
    @Override
    public void setPosition(int x, int y)
    {
//%I+ <136
//        int module = box.getWidth();
//
//        box.setPosition(x, y);
//        redLight.setPosition(x, y);
//        amberLight  .setPosition(x, y + module);
//        greenLight .setPosition(x, y + 2*module);
//%I-
//%A+ >136
        int dx = x - getX();
        int dy = y - getY();
        CM.dontDraw(); {
            box.moveRight(dx);
            box.moveDown (dy);
            redLight  .setPosition(redLight.getX()+dx, redLight.getY()+dy);
            amberLight.setPosition(amberLight  .getX()+dx, amberLight  .getY()+dy);
            greenLight.setPosition(greenLight .getX()+dx, greenLight .getY()+dy);
        } CM.returnDraw();
        xPos = x;
        yPos = y;
//%A-
    }


    // Sada přístupových metod vlastnosti: Rozměr / Modul **********************

    /***************************************************************************
     * Vrátí základní délku, od níž se odvozují všechny rozměry objektu -
     * pro trafficLight je to width box spolu s průměrem jeho světel.
     *
     * @return Šířka box spolu s průměrem světel
     */
    @Override
    public int getModule()
    {
//%I+ <136
//        return box.getWidth();
//%I-
//%A+ >136
        return module;
//%A-
    }


    /***************************************************************************
     * Nastaví nový module představující šířku box a diameter světel.
     *
     * @param module  Nově nastavovaný module
     */
    @Override
    public void setModule(int module)
    {
//%A+ >139
        if (module <= 0) {
            throw new IllegalArgumentException(
                    "\nVelikost modulu musí být nezáporná - zadáno " + module);
        }
//%A-
//%I+ <136
//        box.setSizeInFields(module, 3*module);
//        redLight.setModule (module);
//        amberLight  .setModule (module);
//        greenLight .setModule (module);
//
//        int x = box.getX();
//        int y = box.getY();
//        amberLight .setPosition(x, y + module);
//        greenLight .setPosition(x, y + 2*module);
//        box.setSizeInFields(module, 3*module);
//    }
//
//%I-
//%A+ >136
        int m1 = module;
        int m2 = module / 2;
        int m4 = module / 4;
        int m34= 3 * module / 4;

        Area ref = new Area(xPos, yPos, module, module);
        Area part;

        CM.dontDraw(); {
            //box
            part = new Area(m4, 0, m34, m4);
            part = direction.turnInArea(part, ref);
            this.box.setArea(part);

            //redLight
            part = new Area(m34, 0, m4, m4);
            part = direction.turnInArea(part, ref);
            this.redLight.setPosition(part.x, part.y);
            this.redLight.setModule(part.height);

            //amberLight
            part = new Area(m2, 0, m4, m4);
            part = direction.turnInArea(part, ref);
            this.amberLight.setPosition(part.x, part.y);
            this.amberLight.setModule(part.height);

            //greenLight
            part = new Area(m4, 0, m4, m4);
            part = direction.turnInArea(part, ref);
            this.greenLight.setPosition(part.x, part.y);
            this.greenLight.setModule(part.height);
        } CM.returnDraw();
        this.module = module;
    }


    /***************************************************************************
     * Vrátí direction, do nějž je arrow natočena.
     *
     * @return Směr, do nějž je arrow natočena
     */
    @Override
    public Direction8 getDirection()
    {
        return direction;
    }


    /***************************************************************************
     * Natočí šipku do zadaného směru.
     *
     * @param direction  Směr, do nějž se má arrow natočit
     */
    @Override
    public void setDirection(Direction8 direction)
    {
//%A-
//%A+ >139
        if (! direction.isMain()) {
            throw new IllegalArgumentException(
                "\nNebyl zadán hlavní direction - zadáno " + direction);
        }
//%A-
//%A+ >136
        this.direction = direction;
        this.setModule(module);
    }

//%A-
//%A+ >142

    /***************************************************************************
     * Vrátí state, v němž se trafficLight právě nachází;
     * state trafficLightu určuje, která světla právě svítí.
     *
     * @return Aktuální state trafficLightu
     */
//%A-
//%A+ <"
    @Override
//%A-
//%A+ >142
    public TrafficLightState getState()
    {
        return state;
    }


    /***************************************************************************
     * Nastaví zadaný state trafficLightu, tj. rozvítí světla odpovídající
     * zadanému stavu.
     *
     * @param state Nastavovaný state
     */
//%A-
//%A+ <"
    @Override
//%A-
//%A+ >142
    public void setState(TrafficLightState state)
    {
        //Nemusím nastavovat state - ten nastaví spuštěná metoda
//%A-
//%I+ >142 -143
//        if        (state == LIGHTS_OFF)   {
//            switchOff();
//        } else if (state == ATTENTION) {
//            attention();
//        } else if (state == STOP)  {
//            stop();
//        } else if (state == GET_READY) {
//            getReady();
//        } else if (state == GO) {
//            go();
//        } else if (state == LIGHTS_ON)   {
//            allLightsOn();
//        } else {
//            throw new IllegalArgumentException(
//                "\nZadán neznámý state trafficLightu: " + state);
//        }
//%I-
//%A+ >143
        switch (state)
        {
            case LIGHTS_OFF: allLightsOff();    return;
            case ATTENTION:  attention();       return;
            case STOP:       stop();            return;
            case GET_READY:  getReady();        return;
            case GO:         go();              return;
            case LIGHTS_ON:        allLightsOn();     return;

            default:
                throw new IllegalArgumentException(
                    "\nZadán neznámý state trafficLightu: " + state);
        }
//%A-
//%A+ >142
    }

//%A-


//== OTHER NON-PRIVATE INSTANCE METHODS ========================================

    /***************************************************************************
     * Projde se trafficLightem postupně všemi fázemi standardního cyklu, přičemž
     * countCreated milisekund, po něž trafficLight setrvá v každé fázi je dán velikostí
     * příslušného parametru.
     *
     * @param stop      Doba, po níž bude svítit pouze redLight
     * @param getReady  Doba, po níž bude svítit redLight se žlutou
     * @param go        Doba, po níž bude svítit pouze greenLight
     * @param attention Doba, po níž bude svítit pouze amberLight
     * @param lightsOff Doba, po níž budou všechny světla switchedOff
     */
//%A+ <"
    @Override
//%A-
    public void cycle(int stop, int getReady, int go, int attention, int lightsOff)
    {
        stop();             IO.pause(stop);
        getReady();         IO.pause(getReady);
        go();               IO.pause(go);
        attention();        IO.pause(attention);
        allLightsOff();     IO.pause(lightsOff);
    }


    /***************************************************************************
     * Projde se trafficLightem postupně všemi fázemi standardního cyklu, přičemž
     * se v každé fázi "zdrží" půl vteřiny.
     */
//%A+ <"
    @Override
//%A-
    public void cycle()
    {
        cycle(500, 500, 500, 500, 500);
    }


    /***************************************************************************
     * Prostřednictvím dodaného kreslítka vykreslí obraz své instance.
     *
     * @param painter Painter, které nakreslí instanci
     */
    @Override
    public void paint(Painter painter)
    {
        box        .paint(painter);
        redLight   .paint(painter);
        amberLight .paint(painter);
        greenLight .paint(painter);
    }


    /***************************************************************************
     * Rozsvítí na trafficLightu žlutou a zhasne ostatní světla.
     */
//%A+ <"
    @Override
//%A-
    public void attention()
    {
        redLight   .switchOff();
        amberLight .switchOn();
        greenLight .switchOff();
//%A+ >142
        state = ATTENTION;
//%A-
    }


    /***************************************************************************
     * Rozsvítí na trafficLightu červenou a oranžovou a zhasne zelenou.
     */
//%A+ <"
    @Override
//%A-
    public void getReady()
    {
        redLight   .switchOn();
        amberLight .switchOn();
        greenLight .switchOff();
//%A+ >142
        state = GET_READY;
//%A-
    }


    /***************************************************************************
     * Rozsvítí na trafficLightu červenou a zhasne ostatní světla.
     */
//%A+ <"
    @Override
//%A-
    public void stop()
    {
        redLight   .switchOn();
        amberLight .switchOff();
        greenLight .switchOff();
//%A+ >142
        state = STOP;
//%A-
    }


    /***************************************************************************
     * Rozsvítí na trafficLightu zelenou a zhasne ostatní světla.
     */
//%A+ <"
    @Override
//%A-
    public void go()
    {
        redLight   .switchOff();
        amberLight .switchOff();
        greenLight .switchOn();
//%A+ >142
        state = GO;
//%A-
    }


    /***************************************************************************
     * Zhasne všechna světla trafficLightu.
     */
//%A+ <"
    @Override
//%A-
    public void allLightsOff()
    {
        redLight   .switchOff();
        amberLight .switchOff();
        greenLight .switchOff();
//%A+ >142
        state = LIGHTS_OFF;
//%A-
    }

//%A+ >142

    /***************************************************************************
     * Zhasne všechna světla trafficLightu.
     */
//%A-
//%A+ <"
    @Override
//%A-
//%A+ >142
    public void allLightsOn()
    {
        redLight   .switchOn();
        amberLight .switchOn();
        greenLight .switchOn();
        state = LIGHTS_ON;
    }

//%A-

    /***************************************************************************
     * Vrací textovou reprezentaci (podpis) dané instance
     * používanou především k ladicím účelům.
     *
     * @return Požadovaná textová reprezentace
     */
    @Override
    public String toString()
    {
        return "Semafor_" + ID + "(" + getPosition() + ", module=" + getModule() +
               ", box=" + box.getColor() + ")";
    }



//== PRIVATE AND AUXILIARY CLASS METHODS =======================================
//== PRIVATE AND AUXILIARY INSTANCE METHODS ====================================
//== EMBEDDED TYPES AND INNER CLASSES ==========================================
//== TESTING CLASSES AND METHODS ===============================================
//
//    /***************************************************************************
//     * Test method.
//     */
//    public static void test()
//    {
//        Light inst = new Light();
//    }
//    /** @param args Parametry příkazového řádku - nepoužívané. */
//    public static void main(String[] args)  {  test();  }
    }

//%%- ---- Start of the ovejumped text with closing of the envelope ----
////////////////////////////////////////////////////////////////////////////////
//== TESTING CLASSES AND METHODS ===============================================
//
//    /***************************************************************************
//     * Test method.
//     */
//    public static void test()
//    {
//        new TrafficLight();
//        new TrafficLight(100, 100);
//        new TrafficLight(200,  50, NamedColor.HNĚDÁ);
////        System.exit(0);
//    }
//    /** @param args Parametry příkazového řádku - nepoužívané. */
//    public static void main(String[] args)  {  test();  }
}
